from abc import abstractmethod
from typing import Any
import matplotlib as mpl

# from bs4 import BeautifulSoup
import xml.etree.ElementTree as ET

ET.register_namespace("", "http://www.w3.org/2000/svg")
from io import BytesIO
import pandas as pd
from pandas.io.formats.style import Styler

# todo：支持动态导入
import altair as alt

from . import Template
from . import global_vars
from uuid import uuid4

class Content:

    def __init__(self, value: Any):
        self.value = value

    @abstractmethod
    def display(self) -> str:
        pass
        raise Exception('未实现接口')

    @abstractmethod
    def reset(self,report) :
        pass

    def __str__(self):
        return self.display()

    def __repr__(self) -> str:
        return self.__str__()


class DataFrameStylerContent(Content):

    def __init__(self, value: Styler):
        super().__init__(value)

    @staticmethod
    def test(value: Any) -> bool:
        return isinstance(value, Styler)

    def display(self) -> str:
        # .hide_index()
        return self.value.set_table_attributes("class='dataframe'").render()


class DataFrameContent(DataFrameStylerContent):

    def __init__(self, value: pd.DataFrame):
        super().__init__(value.style)

    @staticmethod
    def test(value: Any) -> bool:
        return isinstance(value, pd.DataFrame)


class MatplotlibFigureContent(Content):
    m_gid_target = '__mpl-data_'
    def __init__(self, value: mpl.figure.Figure):
        super().__init__(value)

    @staticmethod
    def test(value: Any) -> bool:
        return isinstance(value, mpl.figure.Figure)

    @staticmethod
    def findobj_func(obj):
        target = MatplotlibFigureContent.m_gid_target
        id = obj.get_gid()
        if id:
            return obj.get_gid()[:len(target)]==target
        return False

    @staticmethod
    def _set_obj_metadata(fig,xmlid):
        target = MatplotlibFigureContent.m_gid_target
        objs = fig.findobj(MatplotlibFigureContent.findobj_func)

        for obj in objs:
            id = obj.get_gid()
            data = id.lstrip(target)
            xmlid[id].set('data-mpl',data)
            xmlid[id].set('class','mpl-itv')

    @staticmethod
    def mpl_chart2_svg(fig: mpl.figure.Figure):
        f = BytesIO()
        fig.savefig(f, format='svg')
        # bs = BeautifulSoup(f.getvalue(), "xml")
        tree, xmlid = ET.XMLID(f.getvalue())
        tree.set('height','345.6px')
        tree.set('width','460.8px')
        tree.set('preserveAspectRatio','xMinYMin meet')

        MatplotlibFigureContent._set_obj_metadata(fig,xmlid)
        
        return ET.tostring(tree,encoding='unicode')

    def display(self) -> str:
        return MatplotlibFigureContent.mpl_chart2_svg(self.value)


class AltChartContent(Content):

    def __init__(self, value: alt.Chart):
        super().__init__(value)
        self.components_env = global_vars.create_jj2_env_components()

    @staticmethod
    def test(value: Any) -> bool:
        return isinstance(value, alt.TopLevelMixin)

    def reset(self,report) :
        report.has_alt=True

    def display(self) -> str:
        tl = Template.Template('alt_chart.html',self.components_env)
        vars = {
            'vis':f'vis-{uuid4()}',
            'spec': self.value.to_json(),
            }
        tl.set_vars(**vars)
        return str(tl)


_g_mapping = {

}


def get_content(value: Any,report) -> Content:
    pass

    if DataFrameContent.test(value):
        return DataFrameContent(value)

    if DataFrameStylerContent.test(value):
        return DataFrameStylerContent(value)

    if MatplotlibFigureContent.test(value):
        return MatplotlibFigureContent(value)
    if AltChartContent.test(value):
        ret = AltChartContent(value)
        ret.reset(report)
        return ret
    return None
